package com.hyt.it.ogt.kq.main.controller.gov;


import com.alibaba.fastjson.JSON;
import com.hyt.common.apiInfor.ApiResponse;
import com.hyt.it.ogt.kq.common.gov.constant.ResponseCode;
import com.hyt.it.ogt.kq.common.config.exception.KqException;
import com.hyt.it.ogt.kq.common.exception.DataBeingLockedException;
import com.hyt.it.ogt.kq.service.gov.mapper.TimeMapper;
import com.hyt.it.ogt.kq.service.gov.model.dto.TaskTimeRoomArrangeDTO;
import com.hyt.it.ogt.kq.service.gov.model.entity.Task;
import com.hyt.it.ogt.kq.service.gov.model.entity.TimeRoomCandidateReport;
import com.hyt.it.ogt.kq.service.gov.model.param.TimeParam;
import com.hyt.it.ogt.kq.service.gov.model.vo.OfficeRoomVO;
import com.hyt.it.ogt.kq.service.gov.model.vo.TaskRoomToTimeParamVO;
import com.hyt.it.ogt.kq.service.gov.model.vo.TaskTimeRoomArrangeOrNoVO;
import com.hyt.it.ogt.kq.service.gov.model.vo.TimeRoomCodeVO;
import com.hyt.it.ogt.kq.service.gov.service.*;
import com.hyt.it.ogt.kq.common.gov.utils.TextUtil;
import com.hyt.it.ogt.kq.main.controller.base.BaseController;

import com.hyt.loginfo.model.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiOperationSort;
import io.swagger.annotations.ApiSort;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.hyt.it.ogt.kq.common.gov.enums.CacheKeyEnum.CREATE_TASK_TIME_KEY;

/**
 * <p>
 * 批次信息表 前端控制器
 * </p>
 *
 * @author huangyh
 * @since 2021-03-08
 */
@RestController
@Api(tags = "107.批次接口", value = "批次接口")
@ApiSort(value = 107)
@RequestMapping("/kw/gov/time")
@Slf4j
public class TimeController extends BaseController {

    @Autowired
    private ITimeService iTimeService;

    @Resource
    private ITaskRoomService iTaskRoomService;

    @Resource
    private ITimeRoomService iTimeRoomService;

    @Resource
    private ITimeRoomPasswordService iTimeRoomPasswordService;

    @Resource
    private TimeMapper timeMapper;

    @Resource
    private IExamMonitorService iExamMonitorService;

    @Resource
    private ITaskService iTaskService;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private ITimeRoomExcludeService iTimeRoomExcludeService;

    @ApiOperation(
            value = "7.1 添加或编辑批次",
            notes = "30000:添加批次成功; 31201:添加批次异常;"
    )
    @ApiOperationSort(value = 1)
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public ApiResponse<Object> addOrUpdate(@Valid @RequestBody TimeParam timeParam) {
        log.info("# 添加批次参数 ： {}", timeParam.toString());
        User user = getUser();
        if(Objects.isNull(user) || Objects.isNull(user.getId())){
            return ApiResponse.builder()
                    .code(ResponseCode.USER_NOT_LOGIN.getCode())
                    .build();
        }
        String cacheKey = CREATE_TASK_TIME_KEY.getCacheEnumKey(timeParam.getTaskId());
        try {
            // 是否正在生成(分布式锁)，避免多用户操作同一任务
            Boolean creatingFlag = redisTemplate.opsForValue().setIfAbsent(cacheKey, true, CREATE_TASK_TIME_KEY.getExpireSeconds(), TimeUnit.SECONDS);
            if (Boolean.FALSE.equals(creatingFlag)) {
                return ApiResponse.builder()
                        .code(ResponseCode.TIMES_ADD_ING.getCode())
                        .build();
            }
            iTimeService.addOrUpdate(timeParam,user);
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .build();
        } catch (KqException i) {
            log.error("# 添加批次异常: {}", i.getErrMsg());
            return ApiResponse.builder()
                    .code(i.getErrCode())
                    .build();
        } catch (DataBeingLockedException d) {
            return ApiResponse.builder()
                    .code(d.getCode())
                    .build();
        } catch (Exception e) {
            log.error("# 添加批次异常:", e);
            return ApiResponse.builder()
                    .code(ResponseCode.TIMES_ADD_EXCEPTION.getCode())
                    .build();
        } finally {
            redisTemplate.delete(cacheKey);
        }
    }

    @ApiOperation(
            value = "7.2 获取批次(查询条件)",
            notes = "30000:获取批次成功; 43070201:获取批次异常; "
    )
    @ApiOperationSort(value = 2)
    @GetMapping("/getTime")
    public ApiResponse<Object> getTime(String taskId) {
        try {
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .data(timeMapper.selectTimeAll(taskId))
                    .build();
        } catch (Exception e) {
            log.error("获取批次数据异常，",e);
            return ApiResponse.builder()
                    .code(ResponseCode.TIMES_DATA_QUERY_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(
            value = "7.3 获取批次科目(查询条件)",
            notes = "30000:获取批次科目成功; 43070301:获取批次科目异常; "
    )
    @ApiOperationSort(value = 3)
    @GetMapping("/getTimeSubject")
    public ApiResponse<Object> getTimeSubject(String taskId,String timeId) {
        try {
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .data(timeMapper.selectTimeSubject(taskId, timeId))
                    .build();
        } catch (Exception e) {
            log.error("获取批次数据异常，",e);
            return ApiResponse.builder()
                    .code(ResponseCode.TIMES_GET_SUBJECT_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(
            value = "7.4 获取批次考点(查询条件)",
            notes = "30000:获取批次考点成功; 43070401:获取批次考点异常; "
    )
    @ApiOperationSort(value = 4)
    @GetMapping("/getTimePlace")
    public ApiResponse<Object> getTimePlace(String taskId,String timeId) {
        try {
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .data(timeMapper.selectTimePlace(taskId, timeId))
                    .build();
        } catch (Exception e) {
            log.error("获取批次数据异常，",e);
            return ApiResponse.builder()
                    .code(ResponseCode.TIMES_PLACE_QUERY_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(
            value = "7.5 获取批次考点考场(查询条件)",
            notes = "30000:获取批次考点考场成功; 30056:获取批次考点考场异常; "
    )
    @ApiOperationSort(value = 5)
    @GetMapping("/getTimePlaceRoom")
    public ApiResponse<Object> getTimePlaceRoom(String taskId,String timeId,String placeId) {
        try {
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .data(timeMapper.selectTimePlaceRoom(taskId, timeId, placeId))
                    .build();
        } catch (Exception e) {
            log.error("获取批次数据异常，",e);
            return ApiResponse.builder()
                    .code(ResponseCode.TIMES_QUERY_ROOM_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(
            value = "7.6 批次绑定考场",
            notes = "30000:批次绑定考场成功; 30056:批次绑定考场异常; "
    )
    @ApiOperationSort(value = 6)
    @PostMapping("/createTimeRoom")
    public ApiResponse<Object> createTimeRoom(@RequestBody TaskRoomToTimeParamVO taskRoomToTimeParamVO) {
        log.info("# 批次绑定考场参数: " + taskRoomToTimeParamVO.toString());
        try {
            User user = getUser();
            //校验是否存在编排考生
            iTimeRoomService.checkArrangeCandidate(taskRoomToTimeParamVO);

            //生成场次
            iTimeRoomExcludeService.createTimeRoom(taskRoomToTimeParamVO,user);
            //初始化场次密码
            iTimeRoomPasswordService.initTimeRoomPassword(taskRoomToTimeParamVO.getTaskId(),taskRoomToTimeParamVO.getTimeId());
            //初始化监控表
            iExamMonitorService.initExamMonitor(taskRoomToTimeParamVO.getTaskId(),taskRoomToTimeParamVO.getTimeId());
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .build();
        } catch (KqException k) {
            log.error("# 批次绑定考场业务异常: {}", k.getErrMsg());
            if (ResponseCode.TIMES_OVERLAP.getCode().equals(k.getErrCode())) {
                return ApiResponse.builder()
                        .code(k.getErrCode())
                        .data(k.getData())
                        .build();
            }
            return ApiResponse.builder()
                    .code(k.getErrCode())
                    .data(k.getErrMsg())
                    .build();
        } catch (Exception e) {
            log.error("获取批次数据异常，",e);
            return ApiResponse.builder()
                    .code(ResponseCode.TIMES_BIND_ROOM_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(
            value = "7.7 查询考场",
            notes = "30000:查询考场成功; 43070701:查询考场异常; 43070702 考试任务id不能为空"
    )
    @ApiOperationSort(value = 7)
    @PostMapping("/getRoomArrangeOrNo")
    public ApiResponse<Object> getRoomArrangeOrNo(@Valid @RequestBody TaskTimeRoomArrangeDTO taskTimeRoomArrangeDTO, BindingResult bindResult) {
        try {
            if(bindResult.hasErrors()){
                return ApiResponse.builder()
                        .code(ResponseCode.TIMES_QUERY_PARAM.getCode())
                        .data(bindResult.getAllErrors())
                        .build();
            }
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .data(iTaskRoomService.getRoomArrangeOrNo(taskTimeRoomArrangeDTO))
                    .build();
        } catch (Exception e) {
            log.error("获取批次数据异常，",e);
            return ApiResponse.builder()
                    .code(ResponseCode.TIMES_QUERY_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(
            value = "7.8 删除批次",
            notes = "30000:删除批次成功; "
    )
    @ApiOperationSort(value = 8)
    @DeleteMapping("/removeTimeOrSubject")
    public ApiResponse<Object> removeTimeOrSubject(@RequestBody String timeId) {

        try {
            Map<String,String> map = JSON.parseObject(timeId,Map.class);
            String id = map.get("timeId");
            iTimeService.removeTimeOrSubject(id);
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .build();
        } catch (KqException kwGovException) {
            log.error("删除批次业务异常: {}" ,kwGovException.getErrMsg());
            return ApiResponse.builder()
                    .code(kwGovException.getErrCode())
                    .build();
        } catch (Exception e) {
            log.error("删除批次异常，",e);
            return ApiResponse.builder()
                    .code(ResponseCode.TIMES_REMOVE_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(
            value = "7.9 查询批次信息",
            notes = "30000:查询批次信息成功; "
    )
    @ApiOperationSort(value = 9)
    @GetMapping("/getTimeInfo")
    public ApiResponse<Object> getTimeInfo(String taskId) {
        try {
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .data(iTimeService.getTimeInfo(taskId))
                    .build();
        } catch (Exception e) {
            log.error("查询批次信息异常，",e);
            return ApiResponse.builder()
                    .code(ResponseCode.TIMES_ROOM_QUERY_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(
            value = "7.10 根据批次id查询考场信息",
            notes = ""
    )
    @ApiOperationSort(value = 10)
    @GetMapping("/getRoomListByTimeId")
    public ApiResponse<Object> getRoomListByTimeId(@RequestParam String taskId, @RequestParam String timeId) {
        try {
            List<OfficeRoomVO> officeRoomVOList = iTimeService.getRoomListByTimeId(taskId, timeId);
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .data(officeRoomVOList)
                    .build();
        } catch (Exception e) {
            log.error("根据批次id查询考场信息异常，",e);
            return ApiResponse.builder()
                    .code(ResponseCode.TIMES_QUERY_TIMEROOM_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(
            value = "7.11 推送批次数据",
            notes = ""
    )
    @ApiOperationSort(value = 11)
    @GetMapping("/pushTime")
    public ApiResponse<Object> pushTime(@RequestParam String taskId) {
        iTimeService.pushTime(taskId);
        return ApiResponse.builder()
                .code(ResponseCode.SUCCESS.getCode())
                .build();
    }

    @ApiOperation(
            value = "7.12 根据timeId获取考场信息"
    )
    @ApiOperationSort(value = 12)
    @RequestMapping(value = "/selectTimeRoomCodes/{examId}", method = RequestMethod.GET)
    public ApiResponse<Object> selectTimeRoomCodes(@PathVariable String examId) {
        log.info("# 根据timeId获取考场信息参数 ： {}", examId);
        try {
            if (StringUtils.isEmpty(examId)) {
                //批次id不能为空
                return ApiResponse.builder()
                        .code(ResponseCode.PARAM_TIME_ID_CAN_NOT_NULL.getCode())
                        .build();
            }
            List<TimeRoomCodeVO> timeRoomCodeVOList = iTimeRoomService.selectTimeRoomCodes(examId);
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .data(timeRoomCodeVOList)
                    .build();
        } catch (Exception e) {
            log.error("# 根据timeId获取考场信息异常:", e);
            return ApiResponse.builder()
                    .code(ResponseCode.ROOM_DETAIL_INFO_QUERY_BY_ID_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(
            value = "7.13 批次排除考场",
            notes = "20000:批次排除考场成功; 30056:批次绑定考场异常; "
    )
    @ApiOperationSort(value = 6)
    //@PostMapping("/unBindTimeRoom")
    public ApiResponse<Object> unBindTimeRoom(@RequestBody TaskRoomToTimeParamVO taskRoomToTimeParamVO) {
        log.info("# 批次绑定考场参数: " + taskRoomToTimeParamVO.toString());
        try {
            //校验是否存在编排考生
            iTimeRoomService.checkArrangeCandidate(taskRoomToTimeParamVO);

            //生成场次
            iTimeRoomService.unBindTimeRoom(taskRoomToTimeParamVO);
            //初始化场次密码
            iTimeRoomPasswordService.initTimeRoomPassword(taskRoomToTimeParamVO.getTaskId(),taskRoomToTimeParamVO.getTimeId());
            //初始化监控表
            iExamMonitorService.initExamMonitor(taskRoomToTimeParamVO.getTaskId(),taskRoomToTimeParamVO.getTimeId());
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .build();
        } catch (KqException k) {
            log.error("# 批次绑定考场业务异常: {}", k.getErrMsg());
            if (ResponseCode.TIMES_OVERLAP.getCode().equals(k.getErrCode())) {
                return ApiResponse.builder()
                        .code(k.getErrCode())
                        .data(k.getData())
                        .build();
            }
            return ApiResponse.builder()
                    .code(k.getErrCode())
                    .data(k.getErrMsg())
                    .build();
        } catch (Exception e) {
            log.error("获取批次数据异常，",e);
            return ApiResponse.builder()
                    .code(ResponseCode.TIMES_UN_ROOM_EXCEPTION.getCode())
                    .build();
        }
    }
}
